package com.moonbird.springboot.Utils.RecognitionImage;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * 图片文字识别工具类
 */
public class ImageTextRecognitionUtils {
    private static final String REQUEST_URL = "https://cn-east-1.api.xf-yun.com/v1/ocr";
    private static final String API_KEY = "a6e589a40b3eb2bad249c299fb440c5d";
    private static final String API_SECRET = "MTNjM2UxN2NkMmUyZTQzNDIxN2UxOGRm";
    private static final String APP_ID = "f9173867";

    /**
     * 对外暴露的方法，传入图片文件路径和语言类型进行识别
     * @param imagePath 图片文件路径
     * @param language 语言类型，例如 "ch_en" 中英文混合
     * @return 识别到的文本内容
     * @throws Exception 识别过程中可能抛出的异常
     */
    public static String recognizeText(String imagePath, String language) throws Exception {
        String response = doRequest(imagePath, language);
        return extractText(response);
    }

    private static String doRequest(String imagePath, String language) throws Exception {
        URL url = new URL(buildRequestUrl());
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoInput(true);
        connection.setDoOutput(true);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/json");

        try (OutputStream out = connection.getOutputStream()) {
            String params = buildParams(imagePath, language);
            out.write(params.getBytes());
            out.flush();
        }

        try (InputStream is = connection.getInputStream()) {
            return readAllBytes(is);
        } catch (IOException e) {
            try (InputStream errorStream = connection.getErrorStream()) {
                throw new Exception("Request error: " + connection.getResponseMessage() + " " + readAllBytes(errorStream), e);
            }
        }
    }

    private static String buildRequestUrl() {
        try {
            URL url = new URL(REQUEST_URL);
            SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = format.format(new Date());

            String host = url.getHost();
            if (url.getPort() != 80 && url.getPort() != 443) {
                host = host + ":" + url.getPort();
            }

            StringBuilder builder = new StringBuilder()
                    .append("host: ").append(host).append("\n")
                    .append("date: ").append(date).append("\n")
                    .append("POST ").append(url.getPath()).append(" HTTP/1.1");

            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec spec = new SecretKeySpec(API_SECRET.getBytes(Charset.forName("UTF-8")), "HmacSHA256");
            mac.init(spec);
            byte[] hexDigits = mac.doFinal(builder.toString().getBytes(Charset.forName("UTF-8")));
            String sha = Base64.getEncoder().encodeToString(hexDigits);

            String authorization = String.format(
                    "api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                    API_KEY, "hmac-sha256", "host date request-line", sha
            );
            String authBase = Base64.getEncoder().encodeToString(authorization.getBytes(Charset.forName("UTF-8")));

            return String.format("%s?authorization=%s&host=%s&date=%s",
                    REQUEST_URL,
                    URLEncoder.encode(authBase, "UTF-8"),
                    URLEncoder.encode(host, "UTF-8"),
                    URLEncoder.encode(date, "UTF-8")
            );
        } catch (Exception e) {
            throw new RuntimeException("Error assembling request URL: " + e.getMessage(), e);
        }
    }

    private static String buildParams(String imagePath, String language) throws IOException {
        String imageBase64 = Base64.getEncoder().encodeToString(readImage(imagePath));
        return "{" +
                "    \"header\": {" +
                "        \"app_id\": \"" + APP_ID + "\"," +
                "        \"status\": 3" +
                "    }," +
                "    \"parameter\": {" +
                "        \"ocr\": {" +
                "            \"language\": \"" + language + "\"," +
                "            \"ocr_output_text\": {" +
                "                \"encoding\": \"utf8\"," +
                "                \"compress\": \"raw\"," +
                "                \"format\": \"json\"" +
                "            }" +
                "        }" +
                "    }," +
                "    \"payload\": {" +
                "        \"image\": {" +
                "            \"encoding\": \"jpg\"," +
                "            \"image\": \"" + imageBase64 + "\"," +
                "            \"status\": 3" +
                "        }" +
                "    }" +
                "}";
    }

    private static byte[] readImage(String filePath) throws IOException {
        try (InputStream in = new FileInputStream(filePath)) {
            return inputStreamToByteArray(in);
        }
    }

    private static byte[] inputStreamToByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int n;
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }

    private static String readAllBytes(InputStream is) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = is.read(buffer)) != -1) {
            out.write(buffer, 0, bytesRead);
        }
        return out.toString("UTF-8");
    }

    private static String extractText(String response) throws Exception {
        JSONObject jsonObject = JSON.parseObject(response);
        String encodedText = jsonObject.getJSONObject("payload")
                .getJSONObject("ocr_output_text")
                .getString("text");
        String decodedText = new String(Base64.getDecoder().decode(encodedText), "UTF-8");

        // 使用 Gson 解析 JSON
        Gson gson = new Gson();
        JsonObject jsonObject1 = gson.fromJson(decodedText, JsonObject.class);

        // 提取所有页面
        JsonArray pages = jsonObject1.getAsJsonArray("pages");

        StringBuilder extractedText = new StringBuilder();
        // 遍历每一页
        for (JsonElement pageElement : pages) {
            JsonObject page = pageElement.getAsJsonObject();

            // 提取每一页的所有行
            JsonArray lines = page.getAsJsonArray("lines");

            // 遍历每一行
            for (JsonElement lineElement : lines) {
                JsonObject line = lineElement.getAsJsonObject();

                // 提取每一行的所有词
                JsonArray words = line.getAsJsonArray("words");

                // 遍历每一个词
                for (JsonElement wordElement : words) {
                    JsonObject word = wordElement.getAsJsonObject();

                    // 提取词的内容
                    String wordContent = word.get("content").getAsString();
                    extractedText.append(wordContent);
                }
            }
        }

        return extractedText.toString();
    }
}
